package br.unidocs.web.bean;

import java.text.SimpleDateFormat;
import java.util.List;

import javax.ejb.EJB;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.application.Application;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.component.html.HtmlCommandLink;
import javax.faces.component.html.HtmlPanelGroup;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.MethodExpressionActionListener;

import org.apache.myfaces.component.html.ext.HtmlOutputText;

import br.unidocs.modelo.entidade.Mensagem;
import br.unidocs.modelo.entidade.Usuario;
import br.unidocs.servico.MensagemEJB;
import br.unidocs.web.util.WebUtil;

public class MuralDinamicoBackingBean {

	@EJB
	private MensagemEJB mensagemEjb;

	// variaveis para a tela de lista de mensagens
	private List<Mensagem> mensagens;

	// variaveis para detalhamento de mensagem
	private Mensagem mensagemSelecionada;
	private String textoResposta;

	// variaveis para criacao de novo tópico
	private String novoTitulo;
	private String novaMensagem;

	// Número máximo de mensagens no fórum
	// private static final Integer MAX_MENSAGENS_FORUM = 10;

	// PanelGroup raiz - será o componente pai dos outros componentes JSF
	private HtmlPanelGroup pgRaiz;

	// Métodos para criação de componentes JSF dinamicamente
	private HtmlOutputText criaOutputText(String expressaoEL,
			UIComponent componentePai) {
		// Obtém os objetos do framework:

		// A instância atual do FacesContext é utilizada para obter outros
		// objetos e é utilizada em diversos métodos do framework
		FacesContext ctx = FacesContext.getCurrentInstance();

		// Obtém um objeto que gerencia a aplicação JSF da instância atual
		Application app = ctx.getApplication();

		// ExpressionFactory provê a compilação de Expressions Language
		ExpressionFactory elFactory = app.getExpressionFactory();

		// ELContext provê informações de contexto para utilização da Expression
		// Language
		ELContext elCtx = ctx.getELContext();

		// Cria um compenente JSF
		HtmlOutputText componenteJSF = (HtmlOutputText) app
				.createComponent(HtmlOutputText.COMPONENT_TYPE);

		// Cria uma expressão EL
		ValueExpression exp = elFactory.createValueExpression(elCtx,
				expressaoEL, String.class);

		// Associa a expressão EL ao atributo "value" do componente.
		componenteJSF.setValueExpression("value", exp);

		// Relaciona o componente pai com o componente filho
		componentePai.getChildren().add(componenteJSF);

		return componenteJSF;
	}

	private HtmlCommandLink criaCommandLink(String id, String expressaoELValue,
			String expressaoElActionListener, String expressaoELAction,
			UIComponent componentePai) {
		FacesContext ctx = FacesContext.getCurrentInstance();
		Application app = ctx.getApplication();

		HtmlCommandLink componenteJSF = (HtmlCommandLink) app
				.createComponent(HtmlCommandLink.COMPONENT_TYPE);

		// seta o value
		componenteJSF.setValueExpression(
				"value",
				app.getExpressionFactory().createValueExpression(
						ctx.getELContext(), expressaoELValue, String.class));

		// seta o action
		componenteJSF.setActionExpression(app.getExpressionFactory()
				.createMethodExpression(ctx.getELContext(), expressaoELAction,
						String.class, new Class<?>[] {}));

		// seta o action listener
		componenteJSF.addActionListener(new MethodExpressionActionListener(app
				.getExpressionFactory().createMethodExpression(
						ctx.getELContext(), expressaoElActionListener,
						void.class, new Class<?>[] { ActionEvent.class })));
		componenteJSF.setId(id);
		componentePai.getChildren().add(componenteJSF);

		return componenteJSF;

	}

	private UIParameter criaParam(String expressaoEL, UIComponent componentePai) {
		FacesContext ctx = FacesContext.getCurrentInstance();
		Application app = ctx.getApplication();

		UIParameter componenteJSF = (UIParameter) app
				.createComponent(UIParameter.COMPONENT_TYPE);

		componenteJSF.setValueExpression(
				"value",
				app.getExpressionFactory().createValueExpression(
						ctx.getELContext(), expressaoEL, String.class));
		componentePai.getChildren().add(componenteJSF);
		return componenteJSF;
	}

	public HtmlPanelGroup getPgRaiz() {
		if (pgRaiz == null) {
			FacesContext ctx = FacesContext.getCurrentInstance();
			Application app = ctx.getApplication();
			pgRaiz = (HtmlPanelGroup) app
					.createComponent(HtmlPanelGroup.COMPONENT_TYPE);
			// Cria a estrutura de tópicos recursivamente
			criaTopicos(pgRaiz, getMensagens());
		}
		return pgRaiz;
	}

	private String criaTituloLink(Mensagem msg) {
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
		String titulo = sdf.format(msg.getDataCriacao()) + " - "
				+ msg.getTitulo() + " - " + msg.getTexto();
		if (titulo.length() > 150) {
			titulo = titulo.substring(0, 147) + "...";
		}
		return titulo;
	}

	private void criaTopicos(UIComponent componentePai,
			List<Mensagem> listaMensagens) {
		if (listaMensagens.size() > 0) {
			criaOutputText("<ul>", componentePai).setEscape(false);
			for (Mensagem mensagem : listaMensagens) {
				criaOutputText("<li>", componentePai).setEscape(false);

				HtmlCommandLink cmdLink = criaCommandLink(
						"msg" + mensagem.getId(), criaTituloLink(mensagem),
						"#{muralDinamico.selecionaPost}",
						"#{muralDinamico.detalhaPost}", componentePai);
				criaParam(mensagem.getId().toString(), cmdLink);
				criaOutputText("</li>", componentePai).setEscape(false);
				criaTopicos(componentePai, mensagem.getRespostas());
			}
			criaOutputText("</ul>", componentePai).setEscape(false);
		}
	}

	public String detalhaPost() {
		return "post";
	}

	public List<Mensagem> getMensagens() {
		if (mensagens == null) {
			mensagens = mensagemEjb.listarUltimasMensagens(0);
		}
		return mensagens;
	}

	public String vaiParaInicioMural() {
		mensagens = null;
		pgRaiz = null;
		return "mural";
	}

	public void selecionaPost(ActionEvent evt) {
		UIComponent componenteJSF = evt.getComponent();
		UIComponent filho = componenteJSF.getChildren().get(0);
		String id = filho.getAttributes().get("value").toString();
		mensagemSelecionada = mensagemEjb.obterPorId(Integer.valueOf(id));
		novoTitulo = "Re: " + mensagemSelecionada.getTitulo();
	}

	public String postaResposta() {
		FacesContext facesCtx = FacesContext.getCurrentInstance();
		Usuario usuario = facesCtx.getApplication().evaluateExpressionGet(
				facesCtx, "#{loginBean.usuarioLogado}", Usuario.class);

		// Boolean x = true;
		// if (x) {
		// algumacoisa;
		// } else {
		// outra coisa;
		// }
		// x == true ? alguma coisa : outra coisa;
		Mensagem mensagemGravada = mensagemEjb.gravaResposta(
				mensagemSelecionada.getId(),
				usuario == null ? null : usuario.getId(), novoTitulo,
				textoResposta);
		mensagemSelecionada = mensagemGravada;
		novoTitulo = "Re: " + mensagemSelecionada.getTitulo();
		textoResposta = null;
		return "postback";
	}

	public String postaTopico() {
		Usuario usuario = WebUtil.obterUsuarioLogado();

		mensagemEjb.gravaTopico(usuario == null ? null : usuario.getId(),
				novoTitulo, novaMensagem);
		return "mural";
	}

	public void setMensagens(List<Mensagem> mensagens) {
		this.mensagens = mensagens;
	}

	public Mensagem getMensagemSelecionada() {
		return mensagemSelecionada;
	}

	public void setMensagemSelecionada(Mensagem mensagemSelecionada) {
		this.mensagemSelecionada = mensagemSelecionada;
	}

	public String getTextoResposta() {
		return textoResposta;
	}

	public void setTextoResposta(String textoResposta) {
		this.textoResposta = textoResposta;
	}

	public String getNovoTitulo() {
		return novoTitulo;
	}

	public void setNovoTitulo(String novoTitulo) {
		this.novoTitulo = novoTitulo;
	}

	public String getNovaMensagem() {
		return novaMensagem;
	}

	public void setNovaMensagem(String novaMensagem) {
		this.novaMensagem = novaMensagem;
	}

	public void setPgRaiz(HtmlPanelGroup pgRaiz) {
		this.pgRaiz = pgRaiz;
	}

}
